//=============================================================================
// Project  : NIPO Component Framework
// File    : ProcessingChainPlugin.cs
// Author  : Bernhard Dieber (Bernhard.Dieber@uni-klu.ac.at)
// Copyright 2010 by Bernhard Dieber
// This code is published under the Microsoft Public License (Ms-PL).  A copy
// of the license should be distributed with the code.  It can also be found
// at the project website: http://NIPO.CodePlex.com.   This notice, the
// author's name, and all copyright notices must remain intact in all
// applications, documentation, and source files.
//=============================================================================

using System;
using System.Collections.Generic;
using NIPO.Data;
using NIPO.Util;

namespace NIPO.Plugins.Extension
{
    /// <summary>
    /// Enables to build a chain of Processing plugins (works similar to Pipes<![CDATA[&]]>Filters) within a single <see cref="ProcessingPlugin"/>. Data is passed sequentially from one ProcessingPlugin to the other. The output of the last ProcessingPlugin will be taken as Output of the whole processing chain.<br />
    /// This class does not support Input and Output checks.
    /// </summary>
    public class ProcessingChainPlugin:ProcessingPlugin
    {

        private readonly SortedList<int, ProcessingPlugin> _pluginChain = new SortedList<int, ProcessingPlugin>();
        #region Overrides of Plugin

        /// <summary>
        /// A plugin must provide a name
        /// </summary>
        /// <value>The name.</value>
        public override string Name
        {
            get { return "ProcessingChain"; }
        }

        /// <summary>
        /// Every plugin must provide a description on what it does
        /// </summary>
        /// <value>The description.</value>
        public override string Description
        {
            get { return "Chain of Processing Plugins"; }
        }

        /// <summary>
        /// The ConfigurationObject is used to have a user configure a plugin.<br />
        /// Provide here a subclass of PluginConfiguration that defines the configuration values of your need
        /// </summary>
        /// <value>The configuration object.</value>
        public override PluginConfiguration ConfigurationObject
        {
            get { return null; }
            set { ; }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is configured.<br />
        /// "Configured" means that the plugin is ready to run and does not need any additional configuration information
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is configured; otherwise, <c>false</c>.
        /// </value>
        public override bool IsConfigured
        {
            get { return true; }
        }

        /// <summary>
        /// Opportunity for a plugin to do pre-start initialization (e.g. resource allocation, event registration, ...)<br/>
        /// This method is called immediately before the framework start (after checking that IsConfigured == <c>true</c>
        /// </summary>
        /// <remarks>Registration of non-standard events is supposed to happen here. If your plugin is supposed to catch events other than normal data events, this should be done here.</remarks>
        protected internal override void Initialize()
        {
            if (_pluginChain.Count > 1)
            {
                for (int i = 0; i < _pluginChain.Count - 1; i++)
                {
                    _pluginChain[i].NewData += _pluginChain[i + 1].ProcessData;
                }
                _pluginChain[_pluginChain.Count - 1].NewData += ChainFinished;
            }
            else
            {
                _pluginChain[0].NewData += ChainFinished;
            }
            foreach (KeyValuePair<int, ProcessingPlugin> pair in _pluginChain)
            {
                pair.Value.Initialize();
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public override void Dispose()
        {
            _pluginChain.Clear();
        }

        /// <summary>
        /// Resets a PlugIn after a framework run. After this call the plugin must be runnable again
        /// </summary>
        public override void Reset()
        {
            foreach (KeyValuePair<int, ProcessingPlugin> pair in _pluginChain)
            {
                pair.Value.Reset();
            }
        }

        #endregion

        #region Overrides of ProcessingPlugin

        /// <summary>
        /// This function receives data from every InputPlugin for further processing
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="NIPOEventArgs"/> instance containing the event data.</param>
        public override void ProcessData(object sender, NIPOEventArgs e)
        {
            _pluginChain[0].ProcessData(sender,e);
        }

        #endregion


        /// <summary>
        /// EventHandler for <see cref="ProcessingPlugin.NewData"/> of the last plugin
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="NIPO.Data.NIPOEventArgs"/> instance containing the event data.</param>
        private void ChainFinished(object sender, NIPOEventArgs e)
        {
            RaiseNewData(e.Data);
        }

        /// <summary>
        /// Adds a plugin to the plugin chain.
        /// </summary>
        /// <param name="p">The plugin.</param>
        public void AddPlugin(ProcessingPlugin p)
        {
            _pluginChain.Add(_pluginChain.Count, p);
        }
    }
}